package br.com.upper.util;

import br.com.upper.entity.InstanceType;
import br.com.upper.entity.TestConfiguration;

import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.ec2.AmazonEC2Client;
import com.amazonaws.services.ec2.model.BlockDeviceMapping;
import com.amazonaws.services.ec2.model.DescribeInstanceStatusRequest;
import com.amazonaws.services.ec2.model.DescribeInstanceStatusResult;
import com.amazonaws.services.ec2.model.DescribeInstancesRequest;
import com.amazonaws.services.ec2.model.DescribeInstancesResult;
import com.amazonaws.services.ec2.model.EbsBlockDevice;
import com.amazonaws.services.ec2.model.InstanceStatus;
import com.amazonaws.services.ec2.model.InstanceStatusDetails;
import com.amazonaws.services.ec2.model.RunInstancesRequest;
import com.amazonaws.services.ec2.model.RunInstancesResult;
import com.amazonaws.services.ec2.model.TerminateInstancesRequest;
import com.amazonaws.services.ec2.model.TerminateInstancesResult;
import com.amazonaws.services.ec2.model.VolumeType;

public class AWSUtil {
	
	private static AWSUtil instance;
	private static RunInstancesResult currentInstanceResult;
	private static AWSCredentials credentials;
	private static AmazonEC2Client ec2Client;
	private static Long lastTimeChecked;
	
	private AWSUtil() {
		// TODO Auto-generated constructor stub
	}
	
	private static AWSUtil getInstance() {
		if(instance == null) {
			instance = new AWSUtil();
		}
		
		return instance;
	}
	
	public static void runInstance(TestConfiguration configuration) {
		credentials = new BasicAWSCredentials(configuration.getAccessKey(), configuration.getSecretKey());
		ec2Client = new AmazonEC2Client(credentials);
		ec2Client.setEndpoint("ec2.us-east-1.amazonaws.com");
		
		RunInstancesRequest runInstancesRequest = new RunInstancesRequest();
		runInstancesRequest.withImageId(configuration.getImageId());
		runInstancesRequest.withInstanceType(configuration.getInstanceType().getName());
		runInstancesRequest.withMinCount(1);
		runInstancesRequest.withMaxCount(1);
		runInstancesRequest.withKeyName(configuration.getKeyName());
		runInstancesRequest.withSecurityGroupIds(configuration.getSecurityGroupId());
		
		if(configuration.getVolumeType() == br.com.upper.entity.VolumeType.PROVISIONED_IOPS) {	
			
			EbsBlockDevice ebs = new EbsBlockDevice();
			
			Integer provisionedIOPs = configuration.getProvisionedIOPS().intValue();			
			Integer volumeSize = provisionedIOPs/10;
			
			if(provisionedIOPs % 10 != 0) {
				volumeSize++;
			}
			
			ebs.withVolumeSize(volumeSize);
			ebs.withVolumeType(VolumeType.Io1);
			ebs.withIops(configuration.getProvisionedIOPS().intValue());
			ebs.withSnapshotId(configuration.getSnapShotId());
			ebs.withDeleteOnTermination(true);
			BlockDeviceMapping blockDevice = new BlockDeviceMapping();
			blockDevice.withEbs(ebs);
			blockDevice.withDeviceName("/dev/sda1");
			runInstancesRequest.withBlockDeviceMappings(blockDevice);
		}
		
		currentInstanceResult = ec2Client.runInstances(runInstancesRequest);
		
	}

	public static void runInstance(TestConfiguration configuration, InstanceType instanceType) {
		credentials = new BasicAWSCredentials(configuration.getAccessKey(), configuration.getSecretKey());
		ec2Client = new AmazonEC2Client(credentials);
		ec2Client.setEndpoint("ec2.us-east-1.amazonaws.com");
		
		RunInstancesRequest runInstancesRequest = new RunInstancesRequest();
		runInstancesRequest.withImageId(configuration.getImageId());
		runInstancesRequest.withInstanceType(instanceType.getName());
		runInstancesRequest.withMinCount(1);
		runInstancesRequest.withMaxCount(1);
		runInstancesRequest.withKeyName(configuration.getKeyName());
		runInstancesRequest.withSecurityGroupIds(configuration.getSecurityGroupId());
		
		if(configuration.getVolumeType() == br.com.upper.entity.VolumeType.PROVISIONED_IOPS) {	
			
			EbsBlockDevice ebs = new EbsBlockDevice();
			
			Integer provisionedIOPs = configuration.getProvisionedIOPS().intValue();			
			Integer volumeSize = provisionedIOPs/10;
			
			if(provisionedIOPs % 10 != 0) {
				volumeSize++;
			}
			
			ebs.withVolumeSize(volumeSize);
			ebs.withVolumeType(VolumeType.Io1);
			ebs.withIops(configuration.getProvisionedIOPS().intValue());
			ebs.withSnapshotId(configuration.getSnapShotId());
			ebs.withDeleteOnTermination(true);
			BlockDeviceMapping blockDevice = new BlockDeviceMapping();
			blockDevice.withEbs(ebs);
			blockDevice.withDeviceName("/dev/sda1");
			runInstancesRequest.withBlockDeviceMappings(blockDevice);
		}
		
		currentInstanceResult = ec2Client.runInstances(runInstancesRequest);
		
	}
	
	public static void terminateInstance() {
		TerminateInstancesRequest request = new TerminateInstancesRequest();
		request.withInstanceIds(currentInstanceResult.getReservation().getInstances().get(0).getInstanceId());
		ec2Client.terminateInstances(request);
	}
	
	public static RunInstancesResult getCurrentInstanceResult() {
		return currentInstanceResult;
	}
	
	public static boolean checkInstanceRunning() {
		if(isTimeToCheck()) {
			DescribeInstanceStatusRequest req = new DescribeInstanceStatusRequest();
			req.withInstanceIds(currentInstanceResult.getReservation().getInstances().get(0).getInstanceId());
			DescribeInstanceStatusResult result = ec2Client.describeInstanceStatus(req);
			if(result.getInstanceStatuses().size() > 0) {
				
				String instanceState = result.getInstanceStatuses().get(0).getInstanceState().getName();
				String systemState = result.getInstanceStatuses().get(0).getSystemStatus().getStatus();
				
				if(instanceState.equalsIgnoreCase("running") && systemState.equalsIgnoreCase("ok")) {
					return true;
				}			
			}
		}

		return false;
	}
	
	private static boolean isTimeToCheck() {
		long timeAtual = System.currentTimeMillis();
		if(lastTimeChecked == null || (lastTimeChecked != null && ((timeAtual - lastTimeChecked) > 30000))) {
			lastTimeChecked = timeAtual;
			System.out.println(timeAtual + " Checado");
			return true;
		} 
		return false;
	}
	
	
	
	public static String getIP() {
		DescribeInstancesRequest req = new DescribeInstancesRequest();
		req.withInstanceIds(currentInstanceResult.getReservation().getInstances().get(0).getInstanceId());
		DescribeInstancesResult result = ec2Client.describeInstances(req);
		String ip = result.getReservations().get(0).getInstances().get(0).getPrivateIpAddress();
//		String ip = result.getReservations().get(0).getInstances().get(0).getPublicDnsName();
		System.out.println(ip);
		return ip;
	}

}
